package com.wbt.util;


import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Formatter;
import java.util.List;

public class SignatureHelper {

    private static final Logger log = LoggerFactory.getLogger(SignatureHelper.class);
    private static final String HASH_ALGORITHM = "HmacSHA256";

    /**
     * @return
     */
    public static synchronized String nonce() {
        return RandomStringUtils.randomAlphanumeric(8);
    }

    /**
     * @param timestamp
     * @param nonce
     * @param apiKey
     * @return
     */
    public static String generateJoinStr(String timestamp, String nonce, String apiKey) {
        List<String> beforesort = new ArrayList<String>(3);
        beforesort.add(apiKey);
        beforesort.add(timestamp);
        beforesort.add(nonce);

        // 排序
        beforesort.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                try {
                    String s1 = new String(o1.toString().getBytes("GB2312"), "ISO-8859-1");
                    String s2 = new String(o2.toString().getBytes("GB2312"), "ISO-8859-1");
                    return s1.compareTo(s2);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });

        StringBuilder aftersort = new StringBuilder();
        for (int i = 0; i < beforesort.size(); i++) {
            aftersort.append(beforesort.get(i));
        }

        return aftersort.toString();
    }


    /**
     * @param appKey
     * @param appSecret
     * @return
     */
    private static String genEncryptString(String appKey, String appSecret) throws NoSuchAlgorithmException, InvalidKeyException {
        Key secretKey = new SecretKeySpec(appSecret.getBytes(), HASH_ALGORITHM);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);

        //完成hamc-sha256签名
        final byte[] hmac = mac.doFinal(appKey.getBytes());
        StringBuilder sb = new StringBuilder(hmac.length * 2);
        Formatter formatter = new Formatter(sb);

        for (byte b : hmac) {
            formatter.format("%02x", b);
        }

        //完成16进制编码
        return sb.toString();
    }


    /**
     * @param apiKey
     * @param timestamp
     * @param nonce
     * @param signature
     * @return
     */
    public static String sign(String apiKey, String timestamp, String nonce, String signature) {
        return String.format("appkey=%s,timestamp=%s,nonceStr=%s,sign=%s", apiKey, timestamp, nonce, signature);
    }

    /**
     * @param apiKey
     * @param appSecret
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     */
    public static String token(String apiKey, String timestamp, String nonce, String appSecret) throws InvalidKeyException, NoSuchAlgorithmException {

        String genjoinstr = generateJoinStr(timestamp, nonce, apiKey);
        String signature = genEncryptString(genjoinstr, appSecret);

        String sign = sign(apiKey, timestamp, nonce, signature);
        return DigestUtils.md5Hex(sign);
    }

    /**
     * @param appkey
     * @param timestamp
     * @param nonce
     * @param token
     * @return
     */
    public static boolean matchSign(String appkey, String appSecret, String timestamp, String nonce, String token) {

        try {
            String t = token(appkey, timestamp, nonce, appSecret);
            return token.equals(t);
        } catch (InvalidKeyException e) {
            log.error("InvalidKeyException", e);
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException", e);
        }
        return false;
    }


    /**
     * @param apiKey
     * @return
     */
    public static String genauthorization(String apiKey, String appSecret) throws InvalidKeyException, NoSuchAlgorithmException {

        String nonce = nonce();
        String timestamp = Long.toString(System.currentTimeMillis());
        String genjoinstr = generateJoinStr(timestamp, nonce, apiKey);
        String signature = genEncryptString(genjoinstr, appSecret);

        return "appkey=" + apiKey + ",timestamp=" + timestamp + ",nonce=" + nonce + ",sign=" + signature;
    }
}
